require 'rubygems'
require 'simple-oauth'

#プロフィール画像の変更用
require 'open-uri'
require 'net/http'
require 'cgi'

class TwitterClass

	@@debug=true
	@@format='json'

	def initialize(con_key,con_secret,ac_token,ac_token_secret,twitpic_api_key='')
		@access_token = SimpleOAuth.new(con_key,con_secret,ac_token,ac_token_secret)
		@twitpic_api_key = twitpic_api_key
	end

##特殊なもの
	#メッセージをツィートする。
	def update(message='')
		return false if (message=='')
		begin
			response = @access_token.post("http://twitter.com/statuses/update.#{@@format}", 'status'=> message)
		rescue => err
			print_error('update',err,"failed to update [status]#{message}")
			return false
		end
		return true if response.code=='200'
		return false
	end

	#ダイレクトメッセージを送る
	def send_direct(to_user='',message='')
		return false if (to_user=='' or message=='')
		begin
			response = @access_token.post('http://twitter.com/direct_messages/new.json','user'=>to_user,'text'=>message)
		rescue => err
			print_error('send_direct',err,"failed to send [to]#{to_user} [text]#{message}")
			return false
		end
		return true if response.code=='200'
		return false
	end

##POSTメソッド
	def post_message(method,value)
		response = nil
		url='http://twitter.com/'+method+'/'+"#{value}."+@@format
		begin
			response =  @access_token.post(url)
		rescue => err
			print_error('post_message',err,"failed #{method}")
		end
		return response
	end
	
	#tweet_idをReTweet
	def retweet(tweet_id)
		return post_message('statuses/retweet',tweet_id)
	end
	
	#tweet_idをお気に入り登録
	def favorite(tweet_id)
		return post_message('favorites/create',tweet_id)
	end
	
	#user_idをフレンドに（フォローする）
	def follow(user_id)
		return post_message('friendships/create',user_id)
	end
	
	#user_idをフレンドからはずす（アンフォローする）
	def unfollow(user_id)
		return post_message('friendships/destroy',user_id)
	end

##GETメソッド
	#GETのテンプレート
	#'http://twitter.com/"method".json'?"option" の値を返す
	def get_message(method,option='')
		response = nil
		url='http://twitter.com/'+method+'.'+@@format
		url = url+'?'+option if(option!='')
		puts url if(@@debug)
		begin
			response = @access_token.get(url)
		rescue => err
			print_error('get_message',err,"failed #{method}")
		end
		return response
	end

	#認証できているか？
	def verify?()
		response = get_message('account/verify_credentials')
		return true if response.code == '200'
		return false
	end

	#通信できているかテストする
	def connect?()
		response = get_message('help/test')
		return true if (response.body == "\"ok\"")
		return false
	end

	def limit()
		response = get_message('account/rate_limit_status')
		return response.body
	end

	#パブリックタイムラインを取得（count個）
	#返り値はstatus
	def get_public_timeline()
		return get_message('statuses/public_timeline')
	end

	#タイムラインを取得（自分も含む）
	#返り値はstatus
	def get_timeline(option='')
		return get_message('statuses/friends_timeline',option)
	end

	#タイムラインを取得（自分の分だけ）
	#返り値はstatus
	def get_my_timeline(option='')
		return get_message('statuses/user_timeline',option)
	end

	#自分がフォローしてる人の一覧を取得
	#返り値はusers
	def get_friends(option='')
		return get_message('statuses/friends',option)
	end

	#フォローしてくれてる人の一覧を取得
	#返り値はusers
	def get_followers(option='')
		return get_message('statuses/followers',option)
	end
	
	#ダイレクトメッセージの一覧を取得
	#返り値はdirect-messages
	def get_directmessage(option='')
		return get_message('direct_messages',option)
	end

##補助関数
	#statusの中身を全出力
	def dump_status_data(status)
		posted_user = status['user']
		puts ">> #{status['id']} - #{status['created_at']}"
		puts "\t #{status['text']}"
		puts "\t\t #{posted_user['id']}:#{posted_user['name']}(#{posted_user['screen_name']})"  if(posted_user!=nil)
		puts "\t\t   @#{posted_user['location']}:#{posted_user['url']}" if(posted_user!=nil)
	end
	
	#userの中身を全出力
	def dump_user_data(user)
		latest_status = user['status']
		puts ">> #{user['id']} - #{user['created_at']}"
		puts "\t #{user['name']}@#{user['location']}"
		puts "\t #{user['description']}"
		puts "\t image:#{user['profile_image_url']}"
		puts "\t URL:#{user['url']}"
		puts "\t\t #{latest_status['id']} - #{latest_status['created_at']}" if(latest_status!=nil)
		puts " \t\t"#{latest_status['text']}" if(latest_status!=nil)
	end

	#messagesの中身を全出力
	def dump_directmessage_data(message)
		sender_info=message['sender']
		recipient_info=message['recipient']
		puts ">> #{message['id']} - #{message['created_at']}"
		puts "\t To #{message['recipient_screen_name']}(#{message['recipient_id']})"
		puts "\t From #{message['sender_screen_name']}(#{message['sender_id']})"
		puts "\t #{message['text']}"
	end

	#アカウント設定の変更
	#2010/6/7 現在　非公式API
	#返り値はHTLMなので成功か失敗かは自分で判定する
	def account_setting(user)
		begin
			response = @access_token.post('http://twitter.com/account/settings', 'user' => user)
		rescue => err
			print_error('account_setting',err)
		end
		return response
	end

	#リクエストにOAuth Echo用のヘッダを追加
	def add_oauth_echo_heder(request,realm_url,auth_provider_url)
		auth = @access_token.make_auth_header(:GET, auth_provider_url)
		request["X-Auth-Service-Provider"] = auth_provider_url
		request["X-Verify-Credentials-Authorization"] = auth + ", realm=\"#{realm_url}\""
	end

	#リクエストBodyの配列に情報を追加
	def add_form_body(body_array,boundary,key,value)
		body_array << "--#{boundary}"
		body_array << "Content-Disposition: form-data; name=\"#{key}\""
		body_array << ""
		value.split(/\n/).each{|line|
			body_array << "#{line}"
		}
	end
	
	#リクエストBodyの配列にバイナリファイルの情報を追加
	def add_file_body(body_array,boundary,key,file_path)
		file_name = File.basename(file_path)
		mime_type = mime_type(file_name)
		body_array << "--#{boundary}"
		body_array << "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{file_name}\""
		body_array << "Content-Type: #{mime_type}"
		body_array << ""
		open(file_path){|io|
			body_array << io.read
		}
	end

	#MIMEタイプを調べる
	def mime_type(file)
  	case 
    	when file =~ /\.jpg/ then 'image/jpg'
    	when file =~ /\.gif$/ then 'image/gif'
   		when file =~ /\.png$/ then 'image/png'
    	else 'application/octet-stream'
  	end
	end

#### TwitPic関数
	#http://postcard.blog.ocn.ne.jp/itazura/2010/05/twitpic_api_v2_.html
	def twitpic_upload(image_file_path, message = "")
		twitpic_api_url = "http://api.twitpic.com/2/upload.#{@@format}"
		realm_url = "http://api.twitter.com/"
		auth_provider_url = "https://api.twitter.com/1/account/verify_credentials.#{@@format}"

		url_token = URI.parse(twitpic_api_url)
		#認証用ヘッダ追加
		header = @access_token.oauth_echo_header(realm_url,auth_provider_url)
		request = Net::HTTP::Post.new(url_token.request_uri,header)
#
		# construct HTTP request
		boundary = Time.now.strftime("%Y%m%d_%H%M%S_#{$$}")


		#ヘッダ準備
		request["Content-Type"] = "multipart/form-data; boundary=#{boundary}"

		#Bodyの準備はじまり
		body_part = []

		
		#TwitPicのAPI KEY情報を埋め込む
		add_form_body(body_part,boundary,'key',@twitpic_api_key)
		#メッセージを埋め込む
		add_form_body(body_part,boundary,'message',message) if(message!="")
		#画像を埋め込む
		add_file_body(body_part,boundary,'media',image_file_path)

		#おわり
		body_part << "--#{boundary}--"
		body_part << ""
		#「\r\n"」区切りで配列を結合して文字列にする
		request.body = body_part.join("\r\n")

		#ヘッダにbodyのサイズを設定
		request["Content-Length"] = request.body.size
#
		begin
			#送りつける
			http = Net::HTTP.new(url_token.host, url_token.port).start
			response = http.request(request)

			#成功したかどうか確認
			return response.body if response.code=='200'
			return response
		rescue => err
			print_error('twitpic_upload',err)
		end
	end

#### TwitPic関数
	#http://postcard.blog.ocn.ne.jp/itazura/2010/05/twitpic_api_v2_.html
	def profile_upload(image_file_path)
		profile_api_url = "http://api.twitter.com/1/account/update_profile_image.#{@@format}"

		url_token = URI.parse(profile_api_url)
		headers = @access_token.oauth_header(:POST,profile_api_url)
		request = Net::HTTP::Post.new(url_token.request_uri,headers)
#
		# construct HTTP request
		boundary = Time.now.strftime("%Y%m%d_%H%M%S_#{$$}")
		#Bodyの準備はじまり
		body_part = []
		#body_part = "boundary=----#{boundary}"
		request["Content-Type"] = "multipart/form-data; boundary=#{boundary}"

		#画像を埋め込む
		add_file_body(body_part,boundary,'image',image_file_path)

		#おわり
		body_part << "----#{boundary}"
		body_part << ""
		#「\r\n"」区切りで配列を結合して文字列にする
		request.body = body_part.join("\r\n")

		#ヘッダにbodyのサイズを設定
		request["Content-Length"] = request.body.size

		begin
			#送りつける
			http = Net::HTTP.new(url_token.host, url_token.port).start
			response = http.request(request)
			#response = @access_token.post(profile_api_url,body_part,{'Content-Type'=>"multipart/form-data"})

			#成功したかどうか確認
			return response.body if response.code=='200'
			return response
		rescue => err
			print_error('profile_upload',err)
		end
	end



##補助関数

	def print_error(func_name,err,message='')
		time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
		STDERR.print "#{time}\t[Error:#{func_name}]\t #{err} #{message}\n"
	end

end
